A software system refers to a collection of software components such as user applications, application modules, virtual machines, operating systems, etc. (collectively, “programs”) that operate together to perform various tasks. During the execution of the software system, deviations (in terms of functionality, results, performance, throughput, etc.) from a desired or expected behavior of the software system may be observed. Debugging refers to the process of identifying and fixing errors in the programs that cause these deviations in the software system. Many challenges are presented in debugging of software systems during software development.
A programmer can use a program commonly known as a “debugger” to debug another program under development. The debugger can be controlled by reading commands from a debugger script or by receiving debugger instructions directly from the programmer. Debuggers typically support several operations to assist a programmer. A first operation supported by conventional debuggers is an execution control step function which permits a programmer to process program lines, instructions, or statements one at a time to see the results of each program line upon completion. A second operation supported by conventional debuggers is an execution control breakpoint operation which permits a programmer to define a breakpoint as a precise program line, instruction, or statement at which execution of a program can be conditionally or unconditionally halted. A third operation supported by conventional debuggers is a live data manipulation operation which permits a programmer to actively read and write from memory, registers, and other areas of storage to influence program execution. To use a debugger, a programmer will first typically compile the program to be debugged with included debugging information, such as debugging symbols that express which programming-language constructs generated a specific piece of machine code in an executable, resulting in a compiled executable larger than would otherwise be the case. In certain situations where debugging information cannot be compiled into the program under development, utility of a debugger may be limited.
Instead of using a debugger, a programmer can include debugging extensions or plug-ins directly into the program code of the program under development. These debugging extensions can then, after compilation and during execution, export or display data related to program execution for inspection by the programmer. Use of such debugging extensions can avoid the need to compile the program under development with debugging information. However, the use of debugging extensions has its own drawbacks. For example, debugging extensions can be difficult to maintain during initial development, when memory structures in the program under development change frequently. Further, they increase the scope of projects that implement them, insofar as writing debugging extensions can be very time consuming for the programmer. They can become unreliable if there is not a strict process to keep them up-to-date as the program under development evolves. Finally, they can make debugging a program under development very difficult if there is a debugging extension error that compounds a “real” defect in the program under development being debugged with the erroneous debugging extension.
Thus, although both debuggers and debugging extensions help programmers understand errors in programs under development, each conventional technique includes its own drawbacks.